/**
	
	Boxman Game
	
	====================================================================
	Authors: 
		Halili, John Patrick M.
		Laxina, Nathaniel S.
		Villate, Janine D.G.
	Date: 
		March 2011
	Section: 
		CMSC125 ST-6L
	====================================================================
	
*/

#include "../../sdk/dexsdk.h"
#include "../../sdk/time.h"
#include "../../sdk/drawings.h"
#include "../../sdk/levels.h"


#define right 'd'
#define home 'h'
#define left 'a'
#define up 'w'
#define down 's'
#define quitgame 'q'
#define restart 'r'
#define startgame '1'
#define quit '3'
#define instruction '2'
#define x_start_area 60
#define y_start_area 0
#define x_end_area 260
#define y_end_area 200
#define block_size 20
#define xAdd 3
#define yAdd 0
#define MaxLevels 5
#define WHITE 63
#define BLUE 9
#define GREEN 2
#define GRAY 56
#define BLACK 0


/*function prototypes*/
void draw_man(int,int);
int checkGoals();
void erase(int x, int y, int w, int h);
void create_play_area();
void draw_box(int x, int y, int color);
void set_level();
void make_level();
void draw_menu_screen();
void draw_instruction();
void draw_toolBar();
void draw_wallpaper();
void restart_level(int *x, int *y);
int can_move_right(int x, int y);
int can_move_left(int x, int y);
int can_move_up(int x, int y);
int can_move_down(int x, int y);
void showCongrats(char * k);
void winnerAnim();

/*global variables*/
int play_area[block_size][block_size];
int level=1;
int xbound=0,ybound=0;
int xcursor=0,ycursor=0;
int xplayarea=0,yplayarea=0;
int drawing[20][20];
int xGoals[5],yGoals[5];
int numOfGoals;


int main(){
    int x=x_start_area,y=y_start_area,i,j,a,b,ctr;
    char keypress=',';
    int l,k,c=0,flag=0;
    int anim=0;
    set_graphics(VGA_320X200X256);

    do{
       if(keypress!=startgame){
            erase(0,0,400,220);
            draw_menu_screen();
            keypress=(char)getch();
       }
       
       if(keypress==startgame){
			draw_wallpaper();
			draw_toolBar();
			set_level();
			make_level();
			x=xcursor;y=ycursor;
            do{
	            anim=0;
	            draw_man(x,y);
	            keypress=(char)getch();
	               
	            a=(x-x_start_area)/block_size;
	            b=(y-y_start_area)/block_size;
	            if(keypress == right){
                    if(can_move_right(a,b)){
                        if(play_area[a+1][b] == 2){
                            for(ctr=0;ctr<numOfGoals;ctr++){
                                if(a+1==xGoals[ctr] && b==yGoals[ctr]){
	                                play_area[a+1][b] = 3;
	                                break;
								}
                            }if(ctr==numOfGoals) play_area[a+1][b] = 0;
                            play_area[a+2][b] = 2;
                            //check if the box is on a goal  
                            for(ctr=0;ctr<numOfGoals;ctr++){
                                if(a+2==xGoals[ctr] && b==yGoals[ctr]){
	                                drawBoxOnGoal(x+(block_size*2),y);
	                                break;
								}
                            }if(ctr==numOfGoals) drawBox(x+(block_size*2),y); 
                        }
                        for(ctr=0;ctr<numOfGoals;ctr++){
                            if((a==xGoals[ctr] && b==yGoals[ctr])){
	                            drawTarget(x,y);play_area[a][b]=3;
	                            break;
                            }
                        }
	                if(ctr==numOfGoals) drawFloor(x,y);
	                    x+=block_size;
	                    draw_man(x,y);
	                    ctr=0;
	                }
                }else if(keypress == left){
                    if(can_move_left(a,b)){
                        if(play_area[a-1][b] == 2){
                            for(ctr=0;ctr<numOfGoals;ctr++){
                                if(a-1==xGoals[ctr] && b==yGoals[ctr]){
	                                play_area[a-1][b] = 3;
	                                break;
								}
							}if(ctr==numOfGoals) play_area[a-1][b] = 0;
							play_area[a-2][b] = 2;
                            for(ctr=0;ctr<numOfGoals;ctr++){
								if(a-2==xGoals[ctr] && b==yGoals[ctr]){
									drawBoxOnGoal(x-(block_size*2),y);
									break;
                            }
                           }if(ctr==numOfGoals)   drawBox(x-(block_size*2),y);
                        } 
                        for(ctr=0;ctr<numOfGoals;ctr++){
                           if((a==xGoals[ctr] && b==yGoals[ctr])){
								drawTarget(x,y);play_area[a][b]=3;
								break;
							}
						}
					if(ctr==numOfGoals) drawFloor(x,y);
						x-=block_size;
						draw_man(x,y);
					}
				}else if(keypress == down){
					if(can_move_down(a,b)){    
						if(play_area[a][b+1] == 2){
							anim=1;
							for(ctr=0;ctr<numOfGoals;ctr++){
							if(a==xGoals[ctr] && b+1==yGoals[ctr]){
								play_area[a][b+1] = 3;
								break;
							}
							}if(ctr==numOfGoals) play_area[a][b+1] = 0;
							play_area[a][b+2] = 2;
							for(ctr=0;ctr<numOfGoals;ctr++){
								if(a==xGoals[ctr] && b+2==yGoals[ctr]){
									drawBoxOnGoal(x,y+(block_size*2));
									break;
								}
							}if(ctr==numOfGoals) drawBox(x,y+(block_size*2)); 
						}     
                        for(ctr=0;ctr<numOfGoals;ctr++){
							if((a==xGoals[ctr] && b==yGoals[ctr])){
								drawTarget(x,y);play_area[a][b]=3;
								break;
							}
						}
						if(ctr==numOfGoals) draw_box(x,y,BLACK);
							y+=block_size;
							if(anim){drawManDown(x,y);delay(10);}
							draw_man(x,y);
						}
				}else if(keypress == up){
					if(can_move_up(a,b)){
						if(play_area[a][b-1] == 2){
							anim=1;
							for(ctr=0;ctr<numOfGoals;ctr++){
								if(a==xGoals[ctr] && b-1==yGoals[ctr]){
									play_area[a][b-1] = 3;
									break;
								}
							}if(ctr==numOfGoals) play_area[a][b-1] = 0;
                           
							play_area[a][b-2] = 2;
							for(ctr=0;ctr<numOfGoals;ctr++){
								if(a==xGoals[ctr] && b-2==yGoals[ctr]){
									drawBoxOnGoal(x,y-(block_size*2));
									break;
								}
							}if(ctr==numOfGoals) drawBox(x,y-(block_size*2)); 
						}
						for(ctr=0;ctr<numOfGoals;ctr++){
							if((a==xGoals[ctr] && b==yGoals[ctr])){
								drawTarget(x,y);play_area[a][b]=3;
								break;
							}
						}
						if(ctr==numOfGoals) drawFloor(x,y);
							y-=block_size;
                           
							if(anim){drawManUp(x,y);delay(10);}
							draw_man(x,y);
							ctr=0;
						}
				}else if(keypress == restart){
					restart_level(&x, &y); 
				}else if(keypress == quitgame){
					erase(10,60,45,19);
					write_text("Quit?",10,60,63);
					write_text("y/n",30,70,63);
					keypress = (char)getch();
					if(keypress == 'y'){
						keypress = '3';
						break; 
					}else{
						drawWall(0,60);
						drawWall(20,60);
						drawWall(40,60);
						keypress= startgame;
					}
				}else if(keypress == home){
					keypress=',';
					break;
				}
				//check if all boxes were on the targets
				if(checkGoals()){
					level++;
					keypress=startgame;
					break;
                }
			}while(1);
		}else if(keypress==instruction){
			draw_wallpaper();
			draw_instruction();
			keypress==(char)getch();
			if(keypress==startgame);
			else if(keypress==quit) break;
		}
		if(level==MaxLevels+1){
			showCongrats(&keypress);
			level=1;
		}
    }while(keypress != quit);

    set_graphics(VGA_TEXT80X25X16);
    clrscr();
}

void showCongrats(char * k){
    erase(0,0,320,200);
    write_text("You have solved all the levels!",20,60,WHITE);
    delay(200);
    erase(20,60,300,10);
    write_text("GAME OVER",110,70,WHITE);
    winnerAnim();
    *k=',';
}

void winnerAnim(){
	int t;
	for(t=50;t<=300;t+=50){
		if(t%10==0){
			drawMan(3,140,90);
			delay(t-(t-50));
		}else{
			drawMan(0,140,90);
			delay(t-(t-50));
		}
	}
}

void draw_toolBar(){
	erase(30,162,260,36);
	write_text("h-Home",30,165,63);
	write_text("r-Restart",190,165,63); 
	write_text("q-Quit",30,180,63);	
}

void draw_wallpaper(){
	int i=0,j=0;
	for(i=0;i<320;i+=20){
		for(j=0;j<200;j+=20){
			drawWall(i,j);
		}
	}
}

void draw_instruction(){
	erase(30,30,260,140); 
	write_text("INSTRUCTIONS",110,40,25); 
	write_text("Your goal is to move the",400,70,11); 
	write_text("blocks to the drop points",40,80,11);
	//menu options
	write_text("w - Up",50,100,11); 
	write_text("a - Left",130,100,11); 
	write_text("s - Down",50,120,11);
	write_text("d - Right",130,120,11);
	write_text("Press any key to continue",50,160,11);
}

void draw_menu_screen(){
	draw_wallpaper();
	erase(120,38,70,12);
	erase(40,98,80,12);
	erase(40,138,160,12);
	erase(40,178,70,12);
	write_text("SOUKOBAN",120,40,63); //title
	//menu options
	write_text("1 - Start",40,100,63); 
	write_text("2 - Instructions",40,140,63);
	write_text("3 - Quit",40,180,63);
}

void create_play_area(){
    int i,j;
    for(i=x_start_area;i<x_end_area;i++){
        for(j=y_start_area;j<y_end_area;j++){
            write_pixel(i,j,62);
        }
    }
}
void draw_box(int x, int y, int color){
    int i,j;
    for(i=x;i<x+block_size;i++){
        for(j=y;j<y+block_size;j++){
            write_pixel(i,j,color);
        }
    }
}

void draw_man(int x, int y){
    drawMan(0,x,y);
    delay(1);
    drawMan(1,x,y);
    delay(1);
   
}

void erase(int x, int y, int w, int h){ //basically covers an area with a black rectangle 
   int i,j;
	for (i=y;i<=(y+h);i++)
		for (j=x;j<=(x+w);j++)
			write_pixel(j,i,BLACK);
}

void restart_level(int *x, int *y){
	int i,j;
	draw_wallpaper();
	draw_toolBar();
	for(i=0;i<block_size;i++){
		for(j=0;j<block_size;j++){
			play_area[i][j] = 0;
		}
	}
	set_level();
	make_level();
	*x = xcursor; *y = ycursor;
}

int can_move_right(int x, int y){
	if(xcursor+block_size>=x_end_area ||
		play_area[x+1][y] == 1 ||
		(play_area[x+1][y] == 2 && xcursor+(block_size*2)>=x_end_area) ||
		(play_area[x+1][y] == 2 && play_area[x+2][y] == 2) ||
		(play_area[x+1][y] == 2 && play_area[x+2][y] == 1) 
		) return 0; 
	else return 1;
}

int can_move_left(int x, int y){
	if(xcursor<=x_start_area ||
		play_area[x-1][y] == 1 ||
		(play_area[x-1][y] == 2 && xcursor-block_size<=x_start_area) ||
		(play_area[x-1][y] == 2 && play_area[x-2][y] == 2) ||
		(play_area[x-1][y] == 2 && play_area[x-2][y] == 1) 
		) return 0; 
	else return 1;
}

int can_move_down(int x, int y){
	if(ycursor+block_size>=y_end_area ||
		play_area[x][y+1] == 1 ||
		(play_area[x][y+1] == 2 && ycursor+(block_size*2)>=y_end_area) ||
		(play_area[x][y+1] == 2 && play_area[x][y+2] == 1) || 
		(play_area[x][y+1] == 2 && play_area[x][y+2] == 2) 
		) return 0; 
	else return 1;
}

int can_move_up(int x, int y){
	if(ycursor<=y_start_area ||
		play_area[x][y-1] == 1 ||
		(play_area[x][y-1] == 2 && ycursor-block_size<=y_start_area) ||
		(play_area[x][y-1] == 2 && play_area[x][y-2] == 1) ||
		(play_area[x][y-1] == 2 && play_area[x][y-2] == 2)
		) return 0; 
	else return 1;
}

void set_level(){
	int x, y;
	for(x=0;x<10;x++) for(y=0;y<10;y++) play_area[x][y] = 0;
		
	switch(level){
		case 1:
			xbound=8,ybound=8;
			level_1(play_area);
			break;
		case 2:
			xbound=10,ybound=7;
			level_2(play_area);
			break;
		case 3:
			xbound=8;ybound=8;
			level_3(play_area);
			break;
		case 4:
			xbound=9;ybound=7;
			level_4(play_area);
			break;
		case 5:
			xbound=7;ybound=6;
			level_5(play_area);
			break;  
	}
}

int checkGoals(){
   int i;
	for(i=0;i<numOfGoals;i++){
		if(play_area[xGoals[i]][yGoals[i]]==3 || play_area[xGoals[i]][yGoals[i]]==8) return 0;
	}
	if(i==numOfGoals) return 1;
}

void make_level(){
	int i,j;
    int x=xAdd,y=yAdd;
    numOfGoals=0;
    for(i=0;i<xbound;i++){
        for(j=0;j<ybound;j++){
            if(play_area[i][j]==1)drawWall((i+x)*block_size,(j+y)*block_size); //wall
            else if(play_area[i][j]==3){
                drawTarget((i+x)*block_size,(j+y)*block_size); //target
                xGoals[numOfGoals]=i;
                yGoals[numOfGoals++]=j;
            }
            else if(play_area[i][j]==2)drawBox((i+x)*block_size,(j+y)*block_size); //box
            else if(play_area[i][j]==8) {
				draw_man((i+x)*block_size,(j+y)*block_size);
				xcursor=block_size*(i+x);ycursor=block_size*(j+y);
            } //man
            else{
               drawFloor((i+x)*block_size,(j+y)*block_size);
            }
        }
    }
    xplayarea=(x+xbound)*block_size;
    yplayarea=(y+ybound)*block_size;
}
